package ds.safelock.security;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.spec.InvalidKeySpecException;

/**
 * This class provides a MAC computation method
 * which allows you to compute the MAC for one specified data
 * @author David Silva
 * @version 1.0
 */
public class MAC {
	
	/**
	 * Computes the MAC for some given data
	 * @param data the data which the mac will be calculated
	 * @param key the key used to compute the mac (unique MAC for the given key)
	 * @param salt the salt byte array used to digest the key
	 * @return byte array which contains the MAC for data, null if any errors occurs
	 */
	public static byte[] compute(String data, String key, byte[] salt)
	{ return compute(data.getBytes(),key.toCharArray(), salt); }
	
	/**
	 * Computes the MAC for some given data
	 * @param data the data which the mac will be calculated
	 * @param key the key used to compute the mac (unique MAC for the given key)
	 * @param salt the salt byte array used to digest the key
	 * @return byte array which contains the MAC for data, null if any errors occurs
	 */
	public static byte[] compute(byte[] data,char[] key,byte[] salt)
	{
		try
		{
			byte[] keybytes = new String(key).getBytes(ds.safelock.config.Configuration.CHARSET);
			
			/* Instantiate the digest */
			final java.security.MessageDigest shaDigest = java.security.MessageDigest.getInstance(
														  ds.safelock.config.Configuration.DIGEST_ALGORITHM);

			/* mix the salt + key */
			final byte[] salted = new byte[keybytes.length + salt.length];
			System.arraycopy(keybytes, 0, salted, 0, keybytes.length);
			System.arraycopy(salt, 0, salted, keybytes.length, salt.length);
			java.util.Arrays.fill(keybytes, (byte) 0x00);

			/* digest & obtain the final key */
			shaDigest.reset();
			final byte[] finalkey = shaDigest.digest(salted);
			java.util.Arrays.fill(salted, (byte) 0x00);

			/* init key specifications */
			final java.security.spec.KeySpec keyspec = new javax.crypto.spec.PBEKeySpec(
													   new String(finalkey).toCharArray(), salt, 2048, 256);
			
			/* init key factory */
			final javax.crypto.SecretKeyFactory factory = javax.crypto.SecretKeyFactory.getInstance(
														  ds.safelock.config.Configuration.KEYFACTORY_ALGORITHM);
			
			/* obtain the key */
			final javax.crypto.SecretKey secretkey = new javax.crypto.spec.SecretKeySpec(
															factory.generateSecret(keyspec).getEncoded(), 
															ds.safelock.config.Configuration.KEY_ALGORITHM);
			java.util.Arrays.fill(finalkey, (byte) 0x00);

			/* init the MAC */
			final javax.crypto.Mac mac = javax.crypto.Mac.getInstance(ds.safelock.config.Configuration.MAC_ALGORITHM);
			mac.init(secretkey);
			/* computes */
			return mac.doFinal(data);
		}
		catch (java.security.NoSuchAlgorithmException e) { System.out.println(e.getMessage()); }
		catch (UnsupportedEncodingException e) { System.out.println(e.getMessage()); }
		catch (InvalidKeySpecException e) { System.out.println(e.getMessage()); }
		catch (InvalidKeyException e) { System.out.println(e.getMessage()); }
		return null;
	}
	
	/**
	 * Compares two MAC values
	 * @param mac1 MAC to be compared
	 * @param mac2 MAC to be compared
	 * @return true if both MACs match each other, false otherwise
	 */
	public static boolean compareMACs(byte[] mac1, byte[] mac2)
	{
		return java.util.Arrays.equals(mac1, mac2);
	}
	
}
